<?php

class Logger {
        public function __construct( $logfile ) {
        $this->logfile = $logfile;
        $this->open_log();
    }// end: constructor

    public function __destruct() {
        @fflush( $this->fh );
        @fclose( $this->fh );
    }// end: destructor

    public function log( $msg ) {
                // deal with redundant log spam
                if( $msg == $this->last_msg ) {
                        $this->last_msg_count++;
                        return;
                } else if( $this->last_msg_count ) {
                        $this->write( "Last message repeated ".$this->last_msg_count." times." );
                }
                $this->lasg_msg = $msg;
                $this->last_msg_count = 0;

                // actually write the log message out
                $this->write( $msg );
        }// end: log

        private function write( $msg ) {
        $msg = sprintf("[%s] %s\n",date("y-m-d H:i:s"),$msg);
        $succ = @fwrite( $this->fh, $msg );
        if( $succ === FALSE ) {
            echo $msg;
        }
    }// end: write

        private function open_log() {
        if( !file_exists($this->logfile) ) {
            touch( $this->logfile );
            chmod( $this->logfile, 0664 );
        }
        $this->fh = @fopen( $this->logfile, "a" );
    }
}// end: logger class




abstract class Concentre_Daemon_Abstract {

	protected $_uid = 0;
	protected $_gid = 0;
	protected $_home = '/';

	protected $_pid = 0;
// TODO we should generate PID filename automatically, e.g. depends on classname
	protected $_pidfile= '/tmp/daemon.pid';

	protected $_ischildren = false;
	protected $_logger;

	public function __construct($pidfile = null ,$uid = null, $gid = null) {

		if (isset($pidfile)) {
			$this->_pidfile = $pidfile;
		}

        if (isset($uid)) {
        	$this->_uid = $uid;
        }

        if (isset($gid)) {
            $this->_gid = $gid;
        }

		$this->daemon_tag = "launcher";
		$this->_logger = new Logger('/tmp/pcntl.log');		

		error_reporting(0);
		set_time_limit(0);
		
		$this->init();

 		if (false == $this->_foreground) {
		 	$this->_daemonize();
		}

	}

	public function init() {
		$this->log('init');
	}

	public function releaseHandler() {
		if ($this->_ischildren && file_exists($this->_pidfile)) {
			posix_kill($this->_pid, $this->_pidfile);
		        @unlink($this->_pidfile);
		}

	}

	protected function sighandler($signo) {
		switch ($signo) {
			case SIGTERM:
	                        $this->log( "got SIGTERM" );
				$this->stop();
				exit( 0 );
				break;
			case SIGHUP:
				echo "restarting process...\n";
				break;
			default:
		}
	}

        protected function log( $msg, $tag = "launcher" ) {
                $this->_logger->log( $tag.": ".$msg );
        }

	private function _isrunning() {
		$oldPid = @file_get_contents($this->_pidfile);
		return $oldPid !== false && posix_kill(trim($oldPid),0);
        }

	private function _daemonize() {
		if ($this->_isrunning()) {
			echo "Daemon already running ...";
			exit();
		}

		$pid = pcntl_fork();

		if ($pid == -1) {
			die("could not fork");
		} else if ($pid) {
			exit(); // we are the parent
		} else {
 			$this->_ischildren = true;	
			$this->_pid = posix_getpid();
			file_put_contents($this->_pidfile, $this->_pid);
		}

		if (!posix_setgid($this->_gid) || !posix_setuid($this->_uid)) {
        	die('could not set identity');
        }

		if (!posix_setsid()) {
			die("could not detach from terminal");
		}

		
                declare(ticks = 1);
                pcntl_signal( SIGTERM, array(&$this, "sighandler") );

                @chdir($this->_home);
                umask(0);
		
		register_shutdown_function(array(&$this, 'releaseHandler'));
	}

	public function start() {
		$this->_running = true;

		while ($this->_running) {
			$this->main();
			usleep(1000);
		}

	}

//	TODO 'main' method should be declared abstract, 
//		 because functionality will be implemented in the each daemon separately  
	public function main() {
		$this->stop();
	}

	public function stop() {
		$this->_running = false;
		
	}

}

